package com.ysd.lis.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.ysd.common.Result;
import com.ysd.lis.entity.*;
import com.ysd.lis.enums.TestQuestionTypeEnum;
import com.ysd.lis.mapper.WkTestPaperMapper;
import com.ysd.lis.mapper.WkTestUserMapper;
import com.ysd.lis.request.PaperListParams;
import com.ysd.lis.request.TestPaperListDto;
import com.ysd.lis.service.WkTestPaperService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ysd.lis.service.WkTestPaperUserService;
import com.ysd.lis.service.WkTestUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 试卷列表 服务实现类
 * </p>
 *
 * @author LiuQi
 * @since 2024-04-01
 */
@Service
public class WkTestPaperServiceImpl extends ServiceImpl<WkTestPaperMapper, WkTestPaper> implements WkTestPaperService {

    @Autowired
    WkTestPaperMapper wkTestPaperMapper;

    @Autowired
    WkTestUserMapper wkTestUserMapper;

    @Autowired
    WkTestUserService wkTestUserService;

    @Autowired
    WkTestPaperUserService wkTestPaperUserService;

    @Override
    public Result getTestPaperList(String keyWord) {
        MPJLambdaWrapper<WkTestPaper> lambdaQueryWrapper = JoinWrappers.lambda(WkTestPaper.class)
                .selectAll(WkTestPaper.class)
                .selectCollection(WkTestUser.class, WkTestPaper::getSysUserList, map -> map
                        .id(WkTestUser::getUserId, SysUser::getId)
                        .result(WkTestUser::getUserName, SysUser::getRealname)
                        .result(WkTestUser::getIsSign, SysUser::getDiffer))
                .leftJoin(WkTestUser.class, WkTestUser::getPaperId, WkTestPaper::getId)
                .eq(WkTestPaper::getDelFlag, 0)
                .and(StrUtil.isNotEmpty(keyWord), wrapper -> wrapper.like(WkTestPaper::getTestCode, keyWord).or().like(WkTestPaper::getTestTitle, keyWord))
                .orderByAsc(WkTestPaper::getSeq);
        List<WkTestPaper> wkTestPapers = wkTestPaperMapper.selectJoinList(WkTestPaper.class, lambdaQueryWrapper);
        return Result.succ(1, "查询成功！", wkTestPapers);
    }

    @Override
    public Result getPaperView(String paperId) {
        MPJLambdaWrapper<WkTestPaper> lambdaQueryWrapper = JoinWrappers.lambda(WkTestPaper.class)
                .selectAll(WkTestPaper.class)
                .selectCollection(WkTestBig.class, WkTestPaper::getWkTestBigList, b -> b
                        .collection(WkTestSmall.class, WkTestBig::getTestSmallList, c -> c
                                .collection(WkTestOption.class, WkTestSmall::getWkTestOptions)))
                .leftJoin(WkTestBig.class, on -> on.eq(WkTestBig::getPaperId, WkTestPaper::getId).eq(WkTestBig::getDelFlag, 0))
                .leftJoin(WkTestSmall.class, on -> on.eq(WkTestSmall::getBigSubjectId, WkTestBig::getId).eq(WkTestSmall::getDelFlag, 0))
                .leftJoin(WkTestOption.class, on -> on.eq(WkTestOption::getQuestionId, WkTestSmall::getId).eq(WkTestOption::getDelFlag, 0))
                .eq(WkTestPaper::getId, paperId)
                .orderByAsc(WkTestBig::getSeq)
                .orderByAsc(WkTestSmall::getSeq)
                .orderByAsc(WkTestOption::getOptionValue);
        WkTestPaper wkTestPaper = wkTestPaperMapper.selectJoinOne(WkTestPaper.class, lambdaQueryWrapper);
        return Result.succ(1, "查询成功", wkTestPaper);
    }

    /**
     * 查询试卷信息和答案信息
     *
     * @param paperId
     * @return
     */
    @Override
    public Result getPaperListView(String paperId) {
        MPJLambdaWrapper<WkTestPaper> lambdaQueryWrapper = JoinWrappers.lambda(WkTestPaper.class)
                .selectAll(WkTestPaper.class)
                .selectCollection(WkTestBig.class, WkTestPaper::getWkTestBigList, b -> b
                        .collection(WkTestSmall.class, WkTestBig::getTestSmallList, c -> c
                                .association(WkTestPaperUser.class, WkTestSmall::getCheckOption, map -> map
                                        .result(WkTestPaperUser::getOptionValue))
                                .collection(WkTestOption.class, WkTestSmall::getWkTestOptions)))
                .leftJoin(WkTestBig.class, on -> on.eq(WkTestBig::getPaperId, WkTestPaper::getId).eq(WkTestBig::getDelFlag, 0))
                .leftJoin(WkTestSmall.class, on -> on.eq(WkTestSmall::getBigSubjectId, WkTestBig::getId).eq(WkTestSmall::getDelFlag, 0))
                .leftJoin(WkTestPaperUser.class, WkTestPaperUser::getSmallId, WkTestSmall::getId)
                .leftJoin(WkTestOption.class, on -> on.eq(WkTestOption::getQuestionId, WkTestSmall::getId).eq(WkTestOption::getDelFlag, 0))
                .eq(WkTestPaper::getId, paperId)
                .orderByAsc(WkTestBig::getSeq)
                .orderByAsc(WkTestSmall::getSeq)
                .orderByAsc(WkTestOption::getOptionValue);
        WkTestPaper wkTestPaper = wkTestPaperMapper.selectJoinOne(WkTestPaper.class, lambdaQueryWrapper);
        return Result.succ(1, "查询成功", wkTestPaper);
    }

    @Override
    public Result getTestPaperListByUserId(PaperListParams paperListParams) {
        MPJLambdaWrapper<WkTestPaper> lambdaQueryWrapper = JoinWrappers.lambda(WkTestPaper.class)
                .selectAs(WkTestPaper::getId, TestPaperListDto::getId)
                .selectAs(WkTestPaper::getTestCode, TestPaperListDto::getTestCode)
                .selectAs(WkTestPaper::getTestTitle, TestPaperListDto::getTestTitle)
                .selectAs(WkTestPaper::getStatus, TestPaperListDto::getStatus)
                .selectAs(WkTestPaper::getStartDate, TestPaperListDto::getStartDate)
                .selectAs(WkTestPaper::getEndDate, TestPaperListDto::getEndDate)
                .selectAs(WkTestPaper::getTotalScore, TestPaperListDto::getTotalScore)
                .selectAs(WkTestPaper::getDuration, TestPaperListDto::getDuration)
                .selectAs(WkTestPaper::getPaperType, TestPaperListDto::getPaperType)
                .selectAs(WkTestPaper::getSeq, TestPaperListDto::getSeq)
                .selectAs(WkTestUser::getUserName, TestPaperListDto::getUserName)
                .selectAs(WkTestUser::getIsSign, TestPaperListDto::getIsSign)
                .selectAs(WkTestUser::getScore, TestPaperListDto::getScore)
                .leftJoin(WkTestUser.class, WkTestUser::getPaperId, WkTestPaper::getId)
                .eq(WkTestPaper::getDelFlag, 0)
                .eq(StrUtil.isNotEmpty(paperListParams.getUserId()), WkTestUser::getUserId, paperListParams.getUserId())
                .eq(StrUtil.isNotEmpty(paperListParams.getPaperType()), WkTestPaper::getPaperType, paperListParams.getPaperType())
                .and(StrUtil.isNotEmpty(paperListParams.getKeyWord()), wrapper -> wrapper.like(WkTestPaper::getTestCode, paperListParams.getKeyWord()).or().like(WkTestPaper::getTestTitle, paperListParams.getKeyWord()))
                .orderByAsc(WkTestPaper::getSeq);
        List<TestPaperListDto> testPaperListDto = wkTestPaperMapper.selectJoinList(TestPaperListDto.class, lambdaQueryWrapper);
        return Result.succ(1, "查询成功！", testPaperListDto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result addTestPaper(WkTestPaper wkTestPaper) {
        boolean save = this.save(wkTestPaper);
        save = save && saveBatchWkTestPaperUser(wkTestPaper, false);
        if (save) {
            return Result.succ(1, "添加成功！", save);
        } else {
            return Result.fail("添加失败！");
        }
    }

    @Override
    public Result editTestPaper(WkTestPaper wkTestPaper) {
        boolean save = this.updateById(wkTestPaper);
        save = save && saveBatchWkTestPaperUser(wkTestPaper, true);
        if (save) {
            return Result.succ(1, "添加成功！", save);
        } else {
            return Result.fail("添加失败！");
        }
    }

    @Override
    public Result deleteTestPaperByIds(List<String> ids) {
        boolean delete = this.removeByIds(ids);
        if (delete) {
            return Result.succ(1, "添加成功！", delete);
        } else {
            return Result.fail("添加失败！");
        }
    }

    /**
     * 先清空，再插入
     *
     * @param wkTestPaper
     * @param isClear
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatchWkTestPaperUser(WkTestPaper wkTestPaper, boolean isClear) {
        if (CollUtil.isNotEmpty(wkTestPaper.getSysUserList()) && !wkTestPaper.getSysUserList().isEmpty()) {
            if (isClear) {
                LambdaQueryWrapper<WkTestUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(WkTestUser::getPaperId, wkTestPaper.getId());
                wkTestUserMapper.delete(lambdaQueryWrapper);
            }
            final AtomicInteger index = new AtomicInteger(1);
            List<WkTestUser> collect = wkTestPaper.getSysUserList().stream().map(item -> {
                WkTestUser wkTestUser = new WkTestUser();
                wkTestUser.setUserId(item.getId());
                wkTestUser.setUserName(item.getRealname());
                wkTestUser.setIsSign(0);
                wkTestUser.setSeq(index.getAndAdd(1));
                wkTestUser.setPaperId(wkTestPaper.getId());
                return wkTestUser;
            }).collect(Collectors.toList());
            return wkTestUserService.saveBatch(collect);
        }
        return false;
    }

    /**
     * 保存用户答题记录，计算考试成绩
     *
     * @param wkTestPaper
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result saveTestPaperUser(WkTestPaper wkTestPaper) {
        final AtomicInteger totalScore = new AtomicInteger(0);
        Optional.ofNullable(wkTestPaper.getWkTestBigList()).ifPresent(bigList -> {
            List<WkTestSmall> smallList = bigList.stream().flatMap(big -> big.getTestSmallList().stream()).collect(Collectors.toList());
            List<WkTestPaperUser> collect = smallList.stream().map(small -> {
                WkTestPaperUser wkTestPaperUser = new WkTestPaperUser();
                wkTestPaperUser.setPaperId(wkTestPaper.getId());
                wkTestPaperUser.setUserId(wkTestPaper.getUserId());
                wkTestPaperUser.setBigId(small.getBigSubjectId());
                wkTestPaperUser.setSmallId(small.getId());
                TestQuestionTypeEnum predicate = TestQuestionTypeEnum.getValidate(small.getQuestionType());
                wkTestPaperUser.setOptionValue(predicate.getOptionValueFunc().apply(small));
                wkTestPaperUser.setScore(predicate.getFunc().apply(small.getWkTestOptions(), small));
                totalScore.getAndAdd(wkTestPaperUser.getScore() != null ? wkTestPaperUser.getScore() : 0);
                return wkTestPaperUser;
            }).collect(Collectors.toList());
            wkTestPaperUserService.saveBatch(collect);
        });
        // 更新试卷成绩,试卷状态
        LambdaUpdateWrapper<WkTestUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(WkTestUser::getScore, totalScore.longValue())
                .set(WkTestUser::getIsSign, 1)
                .eq(WkTestUser::getPaperId, wkTestPaper.getId())
                .eq(WkTestUser::getUserId, wkTestPaper.getUserId());
        int update = wkTestUserMapper.update(null, updateWrapper);
        return Result.succ(1, "交卷成功！", update);
    }
}
